home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 6 / develop 6 code / TCP / NewsWatcher / NewsWatcher 2.0d15 source / source / tcplow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-26  |  12.6 KB  |  501 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     tcplow.c
  4.  
  5.     This module all the low-level calls to MacTCP.
  6.     
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <stdlib.h>
  13. #include <string.h>
  14.  
  15. #include "MacTCPCommonTypes.h"
  16. #include "TCPPB.h"
  17. #include "AddressXlation.h"
  18. #include "GetMyIPAddr.h"
  19.  
  20. #include "glob.h"
  21. #include "tcplow.h"
  22. #include "util.h"
  23.  
  24.  
  25. pascal    void DNRResultProc (struct hostInfo *hInfoPtr, char *userDataPtr);
  26.  
  27.  
  28. static short gRefNum;
  29.  
  30.  
  31. short GetTCPRefNum (void)
  32. {
  33.     return gRefNum;
  34. }
  35.  
  36.  
  37. static void InitBlock (TCPiopb *pBlock)
  38. {
  39.     memset(pBlock, 0, sizeof(TCPiopb));
  40.     pBlock->ioResult = 1;
  41.     pBlock->ioCRefNum = gRefNum;
  42. }
  43.  
  44.  
  45. static OSErr NewBlock (TCPiopb **pBlock)
  46. {
  47.     *pBlock = (TCPiopb *)MyNewPtr(sizeof(TCPiopb));
  48.     if (MyMemErr() != noErr)
  49.         return MyMemErr();
  50.     InitBlock(*pBlock);
  51.     return noErr;
  52. }
  53.  
  54.  
  55. /* Opens the MacTCP driver.
  56.    This routine must be called prior to any of the below functions. */
  57.  
  58. OSErr OpenTCPDriver (void)
  59. {
  60.     OSErr    err;
  61.     
  62.     err = OpenDriver("\p.IPP",&gRefNum);
  63.     return(err);
  64. }
  65.  
  66.  
  67. /* Creates a new TCP stream in preparation for initiating a connection.
  68.    A buffer must be provided for storing incoming data waiting to be processed */
  69.  
  70. OSErr LowTCPCreateStream (StreamPtr *streamPtr, Ptr connectionBuffer,
  71.     unsigned long connBufferLen, TCPNotifyProc notifPtr)
  72. {
  73.     TCPiopb pBlock;
  74.         
  75.     InitBlock(&pBlock);
  76.     pBlock.csCode = TCPCreate;
  77.     pBlock.csParam.create.rcvBuff = connectionBuffer;
  78.     pBlock.csParam.create.rcvBuffLen = connBufferLen;
  79.     pBlock.csParam.create.notifyProc = notifPtr;
  80.     PBControl((ParmBlkPtr)&pBlock,true);
  81.     while (pBlock.ioResult > 0) GiveTime();
  82.     *streamPtr = pBlock.tcpStream;
  83.     return gCancel ? -1 : pBlock.ioResult;
  84. }
  85.  
  86.  
  87. /* If TCPWaitForConnection is called asynchronously, this command retrieves the 
  88.    result of the call.  It should be called when the above command completes. */
  89.  
  90. OSErr LowFinishTCPWaitForConn (TCPiopb *pBlock, ip_addr *remoteHost,
  91.     tcp_port *remotePort, ip_addr *localHost, tcp_port *localPort)
  92. {    
  93.     OSErr err;
  94.     
  95.     *remoteHost = pBlock->csParam.open.remoteHost;
  96.     *remotePort = pBlock->csParam.open.remotePort;
  97.     *localHost = pBlock->csParam.open.localHost;
  98.     *localPort = pBlock->csParam.open.localPort;
  99.     err = pBlock->ioResult;
  100.     MyDisposPtr((Ptr)pBlock);
  101.     return err;
  102. }
  103.  
  104.  
  105. /* Waits for a connection to be opened on a specified port from a specified address.
  106.    It completes when a connection is made, or a timeout value is reached.  This call
  107.    may be made asynchronously. */
  108.  
  109. OSErr LowTCPWaitForConnection (StreamPtr streamPtr, byte timeout,
  110.     ip_addr *remoteHost, tcp_port *remotePort, ip_addr *localHost,
  111.     tcp_port *localPort, Boolean async, TCPiopb **returnBlock)
  112. {
  113.     OSErr err;
  114.     TCPiopb *pBlock;
  115.     
  116.     if ((err = NewBlock(&pBlock)) != noErr)
  117.         return err;
  118.     
  119.     pBlock->csCode = TCPPassiveOpen;
  120.     pBlock->tcpStream = streamPtr;
  121.     pBlock->csParam.open.ulpTimeoutValue = timeout;
  122.     pBlock->csParam.open.ulpTimeoutAction = 1;
  123.     pBlock->csParam.open.validityFlags = 0xC0;
  124.     pBlock->csParam.open.commandTimeoutValue = timeout;
  125.     pBlock->csParam.open.remoteHost = *remoteHost;
  126.     pBlock->csParam.open.remotePort = *remotePort;
  127.     pBlock->csParam.open.localPort = *localPort;
  128.     PBControl((ParmBlkPtr)pBlock,true);
  129.     if (!async) {
  130.         while (pBlock->ioResult > 0 && GiveTime())
  131.             ;
  132.         err = gCancel ? -1 : pBlock->ioResult;
  133.         if (gCancel) LowTCPAbort(streamPtr);
  134.         LowFinishTCPWaitForConn(pBlock,remoteHost,remotePort,localHost,localPort);
  135.         return err;
  136.     }
  137.     
  138.     *returnBlock = pBlock;
  139.     return noErr;
  140. }
  141.  
  142.  
  143. /* Attempts to initiate a connection with a host specified by host and port. */
  144.  
  145. OSErr LowTCPOpenConnection (StreamPtr streamPtr, byte timeout, 
  146.     ip_addr remoteHost, tcp_port remotePort, ip_addr *localHost,
  147.     tcp_port *localPort)
  148. {
  149.     OSErr err;
  150.     TCPiopb pBlock;
  151.     
  152.     InitBlock(&pBlock);
  153.     pBlock.csCode = TCPActiveOpen;
  154.     pBlock.tcpStream = streamPtr;
  155.     pBlock.csParam.open.ulpTimeoutValue = timeout;
  156.     pBlock.csParam.open.ulpTimeoutAction = 1;
  157.     pBlock.csParam.open.validityFlags = 0xC0;
  158.     pBlock.csParam.open.commandTimeoutValue = timeout;
  159.     pBlock.csParam.open.remoteHost = remoteHost;
  160.     pBlock.csParam.open.remotePort = remotePort;
  161.     pBlock.csParam.open.localPort = *localPort;
  162.     PBControl((ParmBlkPtr)&pBlock,true);
  163.     while (pBlock.ioResult > 0 && GiveTime())
  164.         ;
  165.     *localHost = pBlock.csParam.open.localHost;
  166.     *localPort = pBlock.csParam.open.localPort;
  167.     err = gCancel ? -1 : pBlock.ioResult;
  168.     if (gCancel) LowTCPAbort(streamPtr);
  169.     return err;
  170. }
  171.  
  172.  
  173. /* This routine should be called when a TCPSendData call completes.  It returns the
  174.    error code generated upon completion of the CallTCPSend. */
  175.  
  176. OSErr LowFinishTCPSend (TCPiopb *pBlock)
  177. {
  178.     OSErr err;
  179.     
  180.     err = pBlock->ioResult;
  181.     MyDisposPtr((Ptr)pBlock);
  182.     return err;
  183. }
  184.  
  185.  
  186. /* Sends data through an open connection stream.  Note that the connection must be
  187.    open before any data is sent. This call may be made asynchronously. */
  188.  
  189. OSErr LowTCPSendData (StreamPtr streamPtr, byte timeout, Boolean push,
  190.     Boolean urgent, Ptr wdsPtr, Boolean async, TCPiopb **returnBlock)
  191. {    
  192.     OSErr err;
  193.     TCPiopb *pBlock;
  194.     
  195.     if ((err = NewBlock(&pBlock)) != noErr)
  196.         return err;
  197.     
  198.     pBlock->csCode = TCPSend;
  199.     pBlock->tcpStream = streamPtr;
  200.     pBlock->csParam.send.ulpTimeoutValue = timeout;
  201.     pBlock->csParam.send.ulpTimeoutAction = 1;
  202.     pBlock->csParam.send.validityFlags = 0xC0;
  203.     pBlock->csParam.send.pushFlag = push;
  204.     pBlock->csParam.send.urgentFlag = urgent;
  205.     pBlock->csParam.send.wdsPtr = wdsPtr;
  206.     PBControl((ParmBlkPtr)pBlock,true);
  207.     if (!async) {
  208.         while (pBlock->ioResult > 0 && GiveTime())
  209.             ;
  210.         err = gCancel ? -1 : pBlock->ioResult;
  211.         if (gCancel) LowTCPAbort(streamPtr);
  212.         LowFinishTCPSend(pBlock);
  213.         return err;
  214.     }
  215.     
  216.     *returnBlock = pBlock;
  217.     return noErr;
  218. }
  219.  
  220.  
  221. OSErr LowFinishTCPNoCopyRcv (TCPiopb *pBlock, Boolean *urgent, Boolean *mark)
  222. {
  223.     OSErr err;
  224.     
  225.     *urgent = pBlock->csParam.receive.urgentFlag;
  226.     *mark = pBlock->csParam.receive.markFlag;
  227.     
  228.     err = pBlock->ioResult;
  229.     MyDisposPtr((Ptr)pBlock);
  230.     return err;
  231. }
  232.  
  233.  
  234. OSErr LowTCPNoCopyRcv (StreamPtr streamPtr, byte timeout, Boolean *urgent,
  235.     Boolean *mark, Ptr rdsPtr, short numEntry, Boolean async,
  236.     TCPiopb **returnBlock)
  237. {
  238.     OSErr    err = noErr;
  239.     TCPiopb *pBlock;
  240.     
  241.     if ((err = NewBlock(&pBlock)) != noErr)
  242.         return err;
  243.     
  244.     pBlock->csCode = TCPNoCopyRcv;
  245.     pBlock->tcpStream = streamPtr;
  246.     pBlock->csParam.receive.commandTimeoutValue = timeout;
  247.     pBlock->csParam.receive.rdsPtr = rdsPtr;
  248.     pBlock->csParam.receive.rdsLength = numEntry;
  249.     PBControl((ParmBlkPtr)pBlock,true);
  250.     if (!async) {
  251.         while (pBlock->ioResult > 0 && GiveTime())
  252.             ;
  253.         err = gCancel ? -1 : pBlock->ioResult;
  254.         if (gCancel) LowTCPAbort(streamPtr);
  255.         LowFinishTCPNoCopyRcv(pBlock,urgent,mark);
  256.         return err;
  257.     }
  258.     
  259.     *returnBlock = pBlock;
  260.     return noErr;
  261. }
  262.  
  263.  
  264. OSErr LowTCPBfrReturn (StreamPtr streamPtr, Ptr rdsPtr)
  265. {
  266.     TCPiopb pBlock;
  267.  
  268.     InitBlock(&pBlock);    
  269.     pBlock.csCode = TCPRcvBfrReturn;
  270.     pBlock.tcpStream = streamPtr;
  271.     pBlock.csParam.receive.rdsPtr = rdsPtr;
  272.     PBControl((ParmBlkPtr)&pBlock,true);
  273.     while (pBlock.ioResult > 0) GiveTime();
  274.     return gCancel ? -1 : pBlock.ioResult;
  275. }
  276.  
  277.  
  278. /* If the above is called asynchronously, this routine returns the data that was
  279.    received from the remote host. */
  280.    
  281. OSErr LowFinishTCPRecv (TCPiopb *pBlock, Boolean *urgent, Boolean *mark,
  282.     unsigned short *rcvLen)
  283. {
  284.     OSErr err;
  285.     
  286.     *rcvLen = pBlock->csParam.receive.rcvBuffLen;
  287.     *urgent = pBlock->csParam.receive.urgentFlag;
  288.     *mark = pBlock->csParam.receive.markFlag;
  289.     err = pBlock->ioResult;
  290.     MyDisposPtr((Ptr)pBlock);
  291.     return err;
  292. }
  293.  
  294.  
  295. /* Attempts to pull data out of the incoming stream for a connection. If data is
  296.    not present, the routine waits a specified amout of time before returning with
  297.    a timeout error.  This call may be made asynchronously. */
  298.    
  299. OSErr LowTCPRecvData (StreamPtr streamPtr, byte timeout, Boolean *urgent,
  300.     Boolean *mark, Ptr rcvBuff, unsigned short *rcvLen, Boolean async,
  301.     TCPiopb **returnBlock)
  302. {
  303.     OSErr err;
  304.     TCPiopb *pBlock;
  305.     
  306.     if ((err = NewBlock(&pBlock)) != noErr)
  307.         return err;
  308.     
  309.     pBlock->csCode = TCPRcv;
  310.     pBlock->tcpStream = streamPtr;
  311.     pBlock->csParam.receive.commandTimeoutValue = timeout;
  312.     pBlock->csParam.receive.rcvBuff = rcvBuff;
  313.     pBlock->csParam.receive.rcvBuffLen = *rcvLen;
  314.     PBControl((ParmBlkPtr)pBlock,true);
  315.     if (!async) {
  316.         while (pBlock->ioResult > 0 && GiveTime())
  317.             ;
  318.         err = gCancel ? -1 : pBlock->ioResult;
  319.         if (gCancel) LowTCPAbort(streamPtr);
  320.         LowFinishTCPRecv(pBlock,urgent,mark,rcvLen);
  321.         return err;
  322.     }
  323.     
  324.     *returnBlock = pBlock;
  325.     return noErr;
  326. }
  327.     
  328.  
  329. /* Gracefully closes a connection with a remote host.  This is not always possible,
  330.    and the programmer might have to resort to CallTCPAbort, described next. */
  331.  
  332. OSErr LowTCPClose (StreamPtr streamPtr, byte timeout)
  333. {
  334.     OSErr err;
  335.     TCPiopb pBlock;
  336.  
  337.     InitBlock(&pBlock);    
  338.     pBlock.csCode = TCPClose;
  339.     pBlock.tcpStream = streamPtr;
  340.     pBlock.csParam.close.ulpTimeoutValue = timeout;
  341.     pBlock.csParam.close.validityFlags = 0xC0;
  342.     pBlock.csParam.close.ulpTimeoutAction = 1;
  343.     PBControl((ParmBlkPtr)&pBlock,true);
  344.     while (pBlock.ioResult > 0 && GiveTime())
  345.         ;
  346.     err = gCancel ? -1 : pBlock.ioResult;
  347.     if (gCancel) LowTCPAbort(streamPtr);
  348.     return err;
  349. }
  350.  
  351.  
  352. /* Should be called if a CallTCPClose fails to close a connection properly.
  353.    This call should not normally be used to terminate connections. */
  354.    
  355. OSErr LowTCPAbort (StreamPtr streamPtr)
  356. {
  357.     TCPiopb pBlock;
  358.     
  359.     InitBlock(&pBlock);
  360.     pBlock.csCode = TCPAbort;
  361.     pBlock.tcpStream = streamPtr;
  362.     PBControl((ParmBlkPtr)&pBlock,true);
  363.     while (pBlock.ioResult > 0) GiveTime();
  364.     return gCancel ? -1 : pBlock.ioResult;
  365. }
  366.  
  367. OSErr LowTCPStatus (StreamPtr streamPtr, TCPStatusPB *theStatus)
  368. {
  369.     TCPiopb pBlock;
  370.     
  371.     InitBlock(&pBlock);
  372.     pBlock.csCode = TCPStatus;
  373.     pBlock.tcpStream = streamPtr;
  374.     PBControl((ParmBlkPtr)&pBlock,true);
  375.     while (pBlock.ioResult > 0) GiveTime();
  376.     *theStatus = pBlock.csParam.status;
  377.     return gCancel ? -1 : pBlock.ioResult;
  378. }
  379.  
  380.  
  381. /* Deallocates internal buffers used to hold connection data. This should be
  382.    called after a connection has been closed. */
  383.  
  384. OSErr LowTCPRelease (StreamPtr streamPtr, Ptr *recvPtr, unsigned long *recvLen)
  385. {
  386.     TCPiopb pBlock;
  387.     
  388.     InitBlock(&pBlock);
  389.     pBlock.csCode = TCPRelease;
  390.     pBlock.tcpStream = streamPtr;
  391.     PBControl((ParmBlkPtr)&pBlock,true);
  392.     while (pBlock.ioResult > 0) GiveTime();
  393.     *recvPtr = pBlock.csParam.create.rcvBuff;
  394.     *recvLen = pBlock.csParam.create.rcvBuffLen;
  395.     return gCancel ? -1 : pBlock.ioResult;
  396. }
  397.  
  398. OSErr LowTCPGlobalInfo (Ptr *tcpParam, Ptr *tcpStat)
  399. {
  400.     TCPiopb pBlock;
  401.     
  402.     InitBlock(&pBlock);
  403.     pBlock.csCode = TCPGlobalInfo;
  404.     PBControl((ParmBlkPtr)&pBlock,true);
  405.     while (pBlock.ioResult > 0) GiveTime();
  406.     *tcpParam = (Ptr) pBlock.csParam.globalInfo.tcpParamPtr;
  407.     *tcpStat = (Ptr) pBlock.csParam.globalInfo.tcpStatsPtr;
  408.     return gCancel ? -1 : pBlock.ioResult;
  409. }
  410.  
  411.  
  412. /*    DNRResultProc is the MacTCP domain name resolver completion routine. */
  413.  
  414. static pascal void DNRResultProc (struct hostInfo *hInfoPtr, char *userDataPtr)
  415. {
  416.     *(Boolean*)userDataPtr = true;
  417. }
  418.  
  419.  
  420. /*    LowIPNameToAddr invokes the domain name system to translate a domain name
  421.     into an IP address. */
  422.     
  423. OSErr LowIPNameToAddr (char *name, unsigned long *addr)
  424. {
  425.     struct hostInfo hInfo;
  426.     OSErr err;
  427.     Boolean done=false;
  428.     
  429.     if ((err = OpenResolver(nil)) != noErr) return err;
  430.     err = StrToAddr(name, &hInfo, DNRResultProc, (char*)&done);
  431.     if (err == cacheFault) {
  432.         while (!done) GiveTime();
  433.         err = hInfo.rtnCode;
  434.     }
  435.     CloseResolver();
  436.     *addr = hInfo.addr[0];
  437.     return gCancel ? -1 : err;
  438. }
  439.  
  440.  
  441. /*    LowIPAddrToName invokes the domain name system to translate an IP address
  442.     into a domain name. */
  443.     
  444. OSErr LowIPAddrToName (unsigned long addr, char *name)
  445. {
  446.     struct hostInfo hInfo;
  447.     OSErr err;
  448.     Boolean done=false;
  449.     
  450.     if ((err = OpenResolver(nil)) != noErr) return err;
  451.     err = AddrToName(addr, &hInfo, DNRResultProc, (char*)&done);
  452.     if (err == cacheFault) {
  453.         while (!done) GiveTime();
  454.         err = hInfo.rtnCode;
  455.     }
  456.     CloseResolver();
  457.     hInfo.cname[254] = 0;
  458.     strcpy(name,hInfo.cname);
  459.     return gCancel ? -1 : err;
  460. }
  461.  
  462.  
  463. /* LowGetMyIPAddr returns the IP address of this Mac. */
  464.  
  465. OSErr LowGetMyIPAddr (unsigned long *addr)
  466. {
  467.     struct    IPParamBlock    IPBlock;
  468.     
  469.     memset(&IPBlock, 0, sizeof(IPBlock));
  470.     IPBlock.ioResult = 1;
  471.     IPBlock.csCode = ipctlGetAddr;
  472.     IPBlock.ioCRefNum = gRefNum;
  473.     PBControl((ParmBlkPtr)&IPBlock,true);
  474.     while (IPBlock.ioResult > 0) GiveTime();
  475.     *addr = IPBlock.ourAddress;
  476.     return gCancel ? -1 : IPBlock.ioResult;
  477. }
  478.  
  479.  
  480. /*    LowGetMyIPAddrStr returns the IP address of this Mac as a dotted decimal
  481.     string. */
  482.     
  483. OSErr LowGetMyIPAddrStr (char *addrStr)
  484. {
  485.     unsigned long addr;
  486.     OSErr err;
  487.     static char theAddrStr[16];
  488.     static Boolean gotIt=false;
  489.     
  490.     if (!gotIt) {
  491.         if ((err = LowGetMyIPAddr(&addr)) != noErr) return err;
  492.         if ((err = OpenResolver(nil)) != noErr) return err;
  493.         err = AddrToStr(addr,theAddrStr);
  494.         CloseResolver();
  495.         if (err != noErr) return err;
  496.         gotIt = true;
  497.     }
  498.     strcpy(addrStr,theAddrStr);
  499.     return noErr;
  500. }
  501.